#include "Common.h"
#include "GL/glew.h"
#include "SkyDome.h"
#include "Utils/Logger/Logger.h"

using namespace RayFrame;

RayFrame::SkyDome::SkyDome(int uSeg, int vSeg) :
  m_uSeg(uSeg), m_vSeg(vSeg)
{
  m_texture = NULL;
  buildMesh();
}

RayFrame::SkyDome::~SkyDome()
{

}

void RayFrame::SkyDome::buildMesh()
{
  RefArray<glm::vec3> vertices;
  RefArray<unsigned> vtxIndices;
  RefArray<glm::vec2> texCoord;
  RefArray<unsigned> texIndices;

  const int uSeg = m_uSeg;
  const int vSeg = m_vSeg;
  const float radius = 500;

  // make vertices
  for(int i=0; i<uSeg+1; i++)
  {
    for(int j=0; j<vSeg; j++)
    {
      float u = 2.f * PI / (float)uSeg * i;
      float v = PI * ( 0.5f / (float)(vSeg) * j );
      glm::vec3 pos(cosf(v) * cosf(u), sinf(v), -cosf(v) * sinf(u));
      pos *= radius;
      vertices.Add(pos);
      texCoord.Add(glm::vec2(i/float(uSeg), j/float(vSeg+1)));
    }
  }
  vertices.Add(glm::vec3(0.f, radius, 0.f));
  texCoord.Add(glm::vec2(0.5f, 1));

  // make indices
  for(int i=0; i<uSeg; i++)
  {
    for(int j=1; j<vSeg; j++)
    {
      int v1 = i * (vSeg)+j-1;
      int v2 = (i+1) * (vSeg)+j-1;
      int v3 = v2 + 1;
      int v4 = v1 + 1;
      vtxIndices.Add(v1);
      vtxIndices.Add(v4);
      vtxIndices.Add(v2);

      texIndices.Add(v1);
      texIndices.Add(v4);
      texIndices.Add(v2);

      vtxIndices.Add(v2);
      vtxIndices.Add(v4);
      vtxIndices.Add(v3);

      texIndices.Add(v2);
      texIndices.Add(v4);
      texIndices.Add(v3);
    }
  }

  // create indices near the poles
  int solarIndexN = vertices.GetCount() - 1;
  for(int i=0; i<uSeg; i++)
  {
    const int j = vSeg - 1;
    int v1 = i * (vSeg) + j;
    int v2 = (i+1) * (vSeg) + j;
    int v3 = solarIndexN;
    vtxIndices.Add(v1);
    vtxIndices.Add(v3);
    vtxIndices.Add(v2);

    texIndices.Add(v1);
    texIndices.Add(v3);
    texIndices.Add(v2);
  }

  m_mesh.SetIndicesCount(vtxIndices.GetCount());

  m_mesh.AddStream(TYPE_VERTEX, 3, vertices.GetCount(), (float *) vertices.AbandonArray(),
    vtxIndices.AbandonArray(), true);
  m_mesh.AddStream(TYPE_TEXCOORD, 2, texCoord.GetCount(), (float *) texCoord.AbandonArray(),
    texIndices.AbandonArray(), true);

  if(m_mesh.MakeDrawable() == 0)
    Logger::InstanceRef().Error("Cannot make mesh drawable while creating sky sphere.");
}

void RayFrame::SkyDome::Render( double timeElapsed )
{
  if(m_texture)
  {
    m_texture->Begin();
    m_mesh.Render(timeElapsed);
    m_texture->End();
  }
  else
    m_mesh.Render(timeElapsed);
}
